﻿Imports System.IO

Public Class Photo
    Inherits File

    Overrides Function Text() As String
        Dim S As String = MyBase.Text
        S &= vbTab & "datetaken=" & DateTaken
        S &= vbTab & "rotation=" & Rotation
        S &= vbTab & "size=" & Size
        Return S
    End Function

    Public Overrides Sub Parse(ByVal Item As String)
        DateTaken = Item.Parse("datetaken")
        If Len(DateTaken) > 9 Then Mid(DateTaken, 5, 1) = "-" : Mid(DateTaken, 8, 1) = "-"
        Rotation = Val(Item.Parse("rotation"))
        Size = Item.Parse("size")
    End Sub

    Public Images As New List(Of ImageInfo)

    Function FixAR(ByVal R As Rectangle) As Rectangle
        If R.Width * AR < R.Height Then
            R.Inflate(0, -(R.Height - R.Width * AR) / 2)
        Else
            R.Inflate(-(R.Width - R.Height / AR) / 2, 0)
        End If
        Return R
    End Function

    Dim NoImage As Boolean

    ReadOnly Property BestImage(ByVal HeightNeeded As Integer) As Image
        Get
            Dim Results = (From b In Images Where b.Height >= HeightNeeded Order By b.Height).ToList
            If Results.Any Then Return Results.First.Image
            Results = (From b In Images Order By b.Height Descending).ToList
            If Not Results.Any OrElse Results.First.Height < Me.Height Then AddToStack(Me)
            NoImage = Not Results.Any
            Return If(Results.Any, Results.First.Image, Loading)
        End Get
    End Property

    ReadOnly Property AR As Double
        Get
            Return If(Rotation Mod 2 = 1, Width / Height, Height / Width)
        End Get
    End Property

    Sub Fill(ByVal G As Graphics, ByVal R As Rectangle)
        G.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
        G.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
        Dim Image As Image = BestImage(R.Height)
        G.DrawImage(Image, R)
    End Sub

    Dim TileImages As New SortedList(Of String, Bitmap)

    Dim Biw As Integer
    Overrides Sub Draw(ByVal G As Graphics, ByVal R As Rectangle, ByVal IsSelected As Boolean, ByVal IsHot As Boolean, ByVal IsFocused As Boolean, ByVal IsDropTarget As Boolean)
        Dim t As New Stopwatch
        t.Start()
        G.DrawFocusRect(R, IsSelected, IsHot, IsDropTarget, IsFocused, Item.ListView.Focused)
        R.Inflate(-R.Width \ 24, -R.Height \ 24)
        R.Inflate(-5, -5)
        Dim Thumb As Image = BestImage(R.Height)
        If Thumb.Width / R.Width * R.Height > Thumb.Height Then R.Inflate(0, -(R.Height - R.Width / Thumb.Width * Thumb.Height) / 2) Else R.Inflate(-(R.Width - R.Height / Thumb.Height * Thumb.Width) / 2, 0)
        R.Inflate(5, 5)
        Dim BitmapName As String = Name & R.Width
        If BitmapManager.Exists(BitmapName) AndAlso (Biw < Thumb.Width OrElse NoImage) Then BitmapManager.Remove(BitmapName)
        Biw = Thumb.Width
        If Not BitmapManager.Exists(BitmapName) Then
            Dim z As Rectangle = R
            Dim B As New Bitmap(R.Width, R.Height)
            R.Offset(-R.Left, -R.Top)
            Dim Gr As Graphics = Graphics.FromImage(B)
            Gr.InterpolationMode = Drawing2D.InterpolationMode.High
            Gr.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
            Gr.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
            Gr.DrawShadow(R)
            R.Inflate(-5, -5)
            Gr.DrawImage(Thumb, R)
            'If ShowDates Then
            '    Dim Font As New Font("verdana", 7, FontStyle.Regular)
            '    Dim RR As Rectangle = R
            '    RR.Height \= 6
            '    RR.Offset(0, R.Height * 4 / 6)
            '    RR.Inflate(-4, 0)
            '    Gr.DrawStringBordered(Title & " (" & Size & ")", Font, RR, Color.FromArgb(192, Color.Black), Color.FromArgb(255, 255, 0))
            '    RR = R
            '    RR.Height \= 6
            '    RR.Offset(0, R.Height * 5 / 6)
            '    RR.Inflate(-4, 0)
            '    Gr.DrawStringBordered(Mid(DateTaken, 1, 16), Font, RR, Color.FromArgb(192, Color.Black), Color.FromArgb(255, 255, 255))
            'End If
            BitmapManager.Add(BitmapName, B)
            Gr.Dispose()
            R = z
        End If
        DrawImageWithOpacity(G, BitmapManager.GetBitmap(BitmapName), R, If(IsCut, 0.4, 1))
		'If Studio.Marked.Contains(Me) Then
		'G.DrawString("«", New Font("wingdings", R.Height \ 3), New SolidBrush(Color.FromArgb(128, Color.Yellow)), R)
		'End If
    End Sub

    Dim MaxHeight As Integer = 0
    Sub CacheThumb()
        If Item Is Nothing Then Exit Sub
        If Item.ListView Is Nothing Then Exit Sub
        Dim Folder As String = If(MaxHeight = 0, "thumb", If(MaxHeight < 720, "\hd", If(MaxHeight < 1080, "\fullhd", "")))
        Debug.Print(Folder & "\" & Title)
        With My.Computer.FileSystem
            If Folder = "thumb" Then
                Dim FilePos = GetSetting("PhotoStudio", "Thumbs", Name, "")
                If FilePos = "" Then
                    Dim ThumbName As String = MainFolder & "\sd\" & Title
                    If Not .FileExists(ThumbName) Then
                        If Not .FileExists(MainFolder & "\sd\" & Title) Then Studio.GenerateThumbnails(Title, MainFolder & Title)
                    End If
                    Dim Stream As New FileStream(MainFolder & "\sd\" & Title, FileMode.Open, FileAccess.Read, FileShare.Read)
                    FilePos = BitmapManager.AddThumb(Stream)
                    SaveSetting("PhotoStudio", "Thumbs", Name, FilePos)
                End If
                Dim ImageInfo As New ImageInfo(FilePos, Rotation)
                Images.Add(ImageInfo)
                MaxHeight = ImageInfo.Height
                Debug.Print(MaxHeight)
            Else
                Dim ThumbName As String = .SpecialDirectories.Temp & Folder & "\" & Title
                If Not .FileExists(ThumbName) Then
                    If Not .FileExists(MainFolder & Folder & "\" & Title) Then Studio.GenerateThumbnails(Title, MainFolder & Title)
                    .CopyFile(MainFolder & Folder & "\" & Title, ThumbName)
                End If
                Dim ImageInfo As New ImageInfo(ThumbName, Rotation)
                Images.Add(ImageInfo)
                MaxHeight = ImageInfo.Height
                Debug.Print(MaxHeight)
            End If
        End With
        If Not Item Is Nothing AndAlso Not Item.ListView Is Nothing Then Item.ListView.BeginInvoke(New RedrawDelegate(AddressOf Redraw))
    End Sub

    Delegate Sub RedrawDelegate()

    Dim Rotation As Integer = 0

    Sub Rotate(ByVal d As Integer)
        Rotation = (Rotation + d + 4) Mod 4
        For Each Image In Images
            Image.Rotate(d)
        Next
        Redraw()
    End Sub

    Sub Save(ByVal Path As String)
        My.Computer.FileSystem.CopyFile(MainFolder & "\hd\" & Title, Path & "\" & Title)
    End Sub

    Public Overrides Sub SaveXML(ByVal Doc As System.Xml.XmlTextWriter)
        Doc.WriteAttributeString("date", DateTaken)
        Doc.WriteAttributeString("r", Rotation)
        Doc.WriteAttributeString("size", Size)
    End Sub

    Public Overrides Sub SaveDB()
        ExecSQL("update items set created = @d, rotation = @r, resolution = @s where id = @id", DateTaken, Rotation, Size, ID)
    End Sub

End Class

Public Class ImageInfo
    Dim m_Height As Integer
    Dim m_Width As Integer
    Dim FileName As String
    Dim LastRead As Date
    Dim Rotation As Integer

    Sub New(ByVal Name As String, ByVal Rotation As Integer)
        Me.FileName = Name
        Me.Rotation = Rotation
        Me.m_Width = Image.Width
        Me.m_Height = Image.Height
        MemoryManager.Register(Me)
    End Sub

    Dim m_Image As Image
    ReadOnly Property Image As Image
        Get
            If m_Image Is Nothing Then
                m_Image = Image.FromStream(Stream)
                m_Image.RotateFlip(Rotation)
            End If
            LastRead = Now
            Return m_Image
        End Get
    End Property

    Dim m_Stream As IO.Stream
    ReadOnly Property Stream As Stream
        Get
            If m_Stream Is Nothing Then
                If FileName.Contains("\") Then
                    m_Stream = StreamToMemory(FileName)
                Else
                    m_Stream = BitmapManager.GetThumb(FileName)
                End If
            End If
            Return m_Stream
        End Get
    End Property

    ReadOnly Property Height As Integer
        Get
            Return If(Rotation Mod 2 = 1, m_Width, m_Height)
        End Get
    End Property

    Sub Rotate(ByVal d As Integer)
        Rotation = (Rotation + d) Mod 4
        If Not m_Image Is Nothing Then m_Image.RotateFlip(d)
    End Sub

    Public Function StreamToMemory(ByVal Path As String) As MemoryStream
        Dim Input As New FileStream(Path, FileMode.Open, FileAccess.Read, FileShare.Read)
        Dim Output As New MemoryStream(Input.Length)
        Dim Buffer(Input.Length) As Byte
        Input.Read(Buffer, 0, Input.Length)
        Output.Write(Buffer, 0, Input.Length)
        Input.Close()
        Return Output
    End Function

    Sub Clean()
        If Not m_Image Is Nothing AndAlso Not m_Stream Is Nothing Then
            If DateDiff(DateInterval.Minute, LastRead, Now) >= 1 Then m_Image.Dispose() : m_Image = Nothing
        End If
        If m_Image Is Nothing AndAlso Not m_Stream Is Nothing Then
            If DateDiff(DateInterval.Minute, LastRead, Now) >= 5 Then m_Stream = Nothing
        End If
    End Sub

End Class